/* MenuState.java
 * 
 * Copyright (c) 2009 jmectf
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 
 *   may be used to endorse or promote products derived from this software 
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.jmectf.game.state;

import java.awt.Font;
import java.util.LinkedList;

import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jme.scene.Spatial.LightCombineMode;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jmectf.gui.GFont;
import com.jmectf.gui.GText;
import com.jmex.audio.AudioSystem;
import com.jmex.game.StandardGame;
import com.jmex.game.state.GameState;

/**
 * 
 * @author Nilay Kumar
 * @version Jul 13, 2009 : 4:32:56 PM
 */
public class MenuState extends GameState {

	protected Node rootNode;
	protected KeyBindingManager manager = KeyBindingManager
	.getKeyBindingManager();
	protected StandardGame game;
	protected LinkedList<GText> menuItems;
	protected int previousCursorLocation;
	protected int cursorLocation;
	private final ColorRGBA dark = ColorRGBA.blue;
	private final ColorRGBA light = ColorRGBA.magenta; 

	public MenuState(String name, StandardGame game) {
		menuItems = new LinkedList<GText>();
		this.game = game;
		this.name = name;
		rootNode = new Node(name + ": RootNode");
		ZBufferState buf = DisplaySystem.getDisplaySystem().getRenderer()
		.createZBufferState();
		buf.setEnabled(true);
		buf.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
		rootNode.setRenderState(buf);
		Font menuFont = new Font("Continuum Light", Font.BOLD, 32);
		createMenuElement(menuFont, "Join Game", new Vector3f(200, 300, 0),
				dark, true);
		createMenuElement(menuFont, "Host Game", new Vector3f(200, 250, 0),
				dark, true);
		createMenuElement(menuFont, "Settings", new Vector3f(200, 200, 0),
				dark, true);
		createMenuElement(menuFont, "Quit", new Vector3f(200, 150, 0), dark,
				true);
		createMenuElement(new Font("Continuum Medium", Font.BOLD, 64), "jmectf 0.34",
				new Vector3f(200, 400, 0), ColorRGBA.red, false);
		cursorLocation = previousCursorLocation = 0;
		updateHighlight();
		// initialize key bindings
		bindKeys("move_up", KeyInput.KEY_UP, KeyInput.KEY_LEFT);
		bindKeys("move_down", KeyInput.KEY_DOWN, KeyInput.KEY_RIGHT);
		bindKeys("select", KeyInput.KEY_RETURN);
	}

	private void bindKeys(String command, int... keys) {
		for (int k : keys) {
			manager.add(command, k);
		}
	}

	// preferable to call this in menu order for selectable items
	private void createMenuElement(Font font, String contents,
			Vector3f localTranslation, ColorRGBA color, boolean selectable) {
		GText label = new GText(new GFont(font), 28, 1);
		label.setRenderQueueMode(Renderer.QUEUE_ORTHO);
		label.setText(contents);
		label.setFill(color);
		label.setLightCombineMode(LightCombineMode.Off);
		label.setLocalTranslation(localTranslation);
		getRootNode().attachChild(label);
		getRootNode().updateRenderState();
		if (selectable)
			menuItems.addLast(label);
	}

	// for internal use only
	private void quit() {
		// probably no need, as StandardGame cleans up most stuff
		cleanup();
		AudioSystem.getSystem().cleanup();
		// necessary for a clean exit
		game.finish();
	}

	// highlights current menu item
	private void updateHighlight() {
		GText before = menuItems.get(previousCursorLocation);
		before.setFill(dark);
		GText after = menuItems.get(cursorLocation);
		after.setFill(light);
	}

	// handles selected menu items
	private void handleSelection() {
		GText currentLabel = menuItems.get(cursorLocation);
		if (currentLabel.getText().equals("Quit"))
			quit();
		else
			System.out.println(currentLabel.getText());
	}

	@Override
	public void cleanup() {
	}

	@Override
	public void render(float tpf) {
		DisplaySystem.getDisplaySystem().getRenderer().draw(rootNode);
	}

	@Override
	public void update(float tpf) {
		rootNode.updateGeometricState(tpf, true);
		// check for key presses
		// moving up in the menu
		if (manager.isValidCommand("move_up", false)) {
			previousCursorLocation = cursorLocation;
			if (cursorLocation == 0)
				// if the cursor is out of bounds upwards set it to the lowest
				// menu item (wrap)
				cursorLocation = menuItems.size() - 1;
			else
				// otherwise just decrement the position
				cursorLocation--;
			updateHighlight();
		}
		// moving down in the menu
		if (manager.isValidCommand("move_down", false)) {
			previousCursorLocation = cursorLocation;
			if (cursorLocation == menuItems.size() - 1)
				// if the cursor is out of bounds downwards set it to the
				// highest item (wrap)
				cursorLocation = 0;
			else
				// otherwise just increment the position
				cursorLocation++;
			updateHighlight();
		}
		// selecting a menu item
		if (manager.isValidCommand("select", false)) {
			// handle menu selection items here
			handleSelection();
		}
	}

	public Node getRootNode() {
		return rootNode;
	}

}
